Home About
It's A Blog Banner Text

HowTo! - Create a New Script File from a Session-Defined Function

Sometimes when I'm working in an interactive PowerShell session, I define a function on the fly to help with whatever task I'm currently doing.

When I'm struck with a moment of true inspiration and I have created a function that I'd actually like to keep around and use again once this session ends, I want the ability to add that to my profile.

I keep all my profile functions defined as individual files and use a build script to add them all to my actual profile, so while working the other day I decided to write a function for creating those function scripts from functions that I've defined in the interactive session.

Here it is:

Function NewFunction {
<# 
  .SYNOPSIS
    Creates a new PowerShell function file with the specified name and script block.
  .DESCRIPTION
    This function generates a new PowerShell script file containing a function definition based on the provided name and script block.
  .PARAMETER FunctionName
    The name of the function to create.
  .PARAMETER ScriptBlock
    The script block that defines the body of the function.
  .PARAMETER OutputDirectory
    The directory where the new function file will be saved. Defaults to "$env:GitRepos\PowerShellCustomization\Functions".
  .EXAMPLE
    NewFunction -FunctionName "Get-HelloWorld" -ScriptBlock { Write-Output "Hello, World!" }
    This command creates a new function file named "Get-HelloWorld.ps1" in the default output directory with the specified script block.
  .EXAMPLE
    NewFunction Get-HelloWorld { Write-Output "Hello, World!" }
    This command creates a new function file named "Get-HelloWorld.ps1", and makes use of the positional parameters.
    This is useful for creating a file for a function you've created in the console by simply adding "New" in front of "Function".
#>  
  param(
    [Parameter(Position = 0, Mandatory = $true, HelpMessage = "Name of the function to create")]  
    [String]$FunctionName,

    [Parameter(Position = 1, Mandatory = $true, HelpMessage = "ScriptBlock defining the function body")]
    [scriptblock]$ScriptBlock,

    [Parameter(Position = 2, Mandatory = $false, HelpMessage = "Output path for the function file")]
    [string]$OutputDirectory = ".\",

    [Parameter(Position = 3, Mandatory = $false, HelpMessage = "Append to the file if it already exists")]
    [switch]$Append
  )

  $outFileContent = @"
Function $FunctionName {
  $ScriptBlock
}
"@
  $outFilePath = [System.IO.Path]::Combine("$OutputDirectory", "$FunctionName.ps1")

  $outFileParams = @{
    FilePath = $outFilePath
    InputObject = $outFileContent
  }

  If ($PSBoundParameters['Append']) {
    $outFileParams['Append'] = $true
  }
  
  Out-File @outFileParams
}

NewFunction

The function is called NewFunction. While yes, this does not conform to best practices of function naming conventions, I liked the idea that I could create a file for a function I've defined in the console by simply adding "New" in front of "Function".

This allows me to just hit the up arrow to get the last function I defined, type "New" at the begining of the first line, hit enter and I'm done.

The thought of haveing to also add a dash after "New" was unbearable.

The function takes four parameters:

I added the -Append parameter after realizing that it might be useful in scenarios where you store all your custom functions in your profile. You could then do something like this to simply append the fucntion to your profile:

NewFunction Hello-World { Write-Output "Hello, World!" } -OutputDirectory $profile -Append

Using $PSDefaultParameterValues to Set Default Parameters

This is a good time to remind ourselves about $PSDefaultParameterValues.

If you often use the same parameters with certain cmdlets, you can set default values for those parameters using $PSDefaultParameterValues.

For example, I usually like to make sure that no matter what version of PowerShell I'm using, Install-Module and Install-PSResource always run with -Scope AllUsers as I like to keep all my modules in the Program Files location. So I have this set in my profile:

$PSDefaultParameterValues.Add('Install-Module:Scope', 'AllUsers')
$PSDefaultParameterValues.Add('Install-PSResource:Scope', 'AllUsers')

This makes it so if I don't specify the -Scope parameter when I run those cmdlets, it will automatically use AllUsers.

We can use the $PSDefaultParameterValues to set the default output directory for the NewFunction cmdlet so we don't have to keep specifying it.

If you want to always append your function directly to your profile, you can add this to your profile:

$PSDefaultParameterValues.Add('NewFunction:OutputDirectory', $profile)
$PSDefaultParameterValues.Add('NewFunction:Append', $true)

Now when running something like this:

NewFunction Hello-World { Write-Output "Hello, World!" }

It will automatically append the Hello-World function in your profile script (or create a profile script if it doesn't already exist).

Ta-da!